/*
 * FileName：UserTagCtrl.java 
 * <p>
 * Copyright (c) 2017-2020 <a href="https://www.smartwx.info">hermit(1154808491@qq.com)</a>.
 * <p>
 * Licensed under the GNU General Public License, Version 3 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/gpl-3.0.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package com.smart.wx.wxcms.ctrl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.common.collect.ImmutableMap;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.smart.common.BaseCtrl;
import com.smart.common.Constants;
import com.smart.common.exception.WxErrorException;
import com.smart.common.util.AjaxResult;
import com.smart.wx.wxapi.process.MpAccount;
import com.smart.wx.wxapi.process.WxApi;
import com.smart.wx.wxapi.process.WxApiClient;
import com.smart.common.util.WxMemoryCacheClient;
import com.smart.wx.wxcms.entity.AccountFans;
import com.smart.wx.wxcms.entity.TagToFan;
import com.smart.wx.wxcms.entity.UserTag;
import com.smart.wx.wxcms.service.AccountFansService;
import com.smart.wx.wxcms.service.UserTagService;


/**
 * @author fuziKong
 * @version 2.0
 * @date 2018-05-30 10:54:58
 */
@Controller
@RequestMapping("/userTag")
public class UserTagCtrl extends BaseCtrl {

    private Logger logger = LoggerFactory.getLogger(UserTagCtrl.class);
    @Autowired
    private UserTagService userTagService;
    @Autowired
    private AccountFansService accountFansService;

    private Object lock = new Object();

    /**
     * 根据用户标签获取粉丝列表
     *
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/getUserListByTag")
    @ResponseBody
    public AjaxResult getUserListByTag(Integer id) throws WxErrorException {
        logger.info("根据用户标签获取粉丝列表 id:{}", id);
        UserTag tag = userTagService.getById(id);
        TagToFan ttf = new TagToFan();
        ttf.setAccount(tag.getAccount());
        ttf.setTagId(tag.getTagId());
        List<AccountFans> fansList = accountFansService.getFansByTagId(ttf);
        return AjaxResult.success(fansList);
    }

    /**
     * 同步标签下的用户
     *
     * @param id
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/syncUsersByTag")
    @ResponseBody
    public AjaxResult syncUsersByTag(Integer id) throws WxErrorException {
        logger.info("同步标签下的用户 id:{}", id);
        UserTag tag = userTagService.getById(id);


        synchronized (lock) {
            //根据tag清空中间表
            userTagService.deleteTTF(TagToFan.builder().tagId(tag.getTagId()).build());
            List<String> list = forFansByTag(new ArrayList<String>(), tag.getTagId(), "");
            MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
            if (list != null && !list.isEmpty()) {
                List<TagToFan> listTTF = new ArrayList<TagToFan>();
                for (int i = 0; i < list.size(); i++) {
                    TagToFan ttf = new TagToFan();
                    ttf.setTagId(tag.getTagId());
                    ttf.setOpenId(list.get(i));
                    ttf.setAccount(mpAccount.getAccount());
                    listTTF.add(ttf);
                }
                userTagService.addTagToUserList(listTTF);
            }
        }
        return AjaxResult.success();
    }

    //递归获取标签下的粉丝
    public static List<String> forFansByTag(List<String> list, int id, String openId) throws WxErrorException {
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
        JSONObject tagId = new JSONObject();
        tagId.put("tagid", id);
        tagId.put("next_openid", openId);
        JSONObject jsonObjUserList = WxApiClient.getUserListByTag(tagId.toString(), mpAccount);
        if (jsonObjUserList.getIntValue("count") != 0) {
            //要把本次的数据添加进去
            JSONObject data = (JSONObject) jsonObjUserList.get("data");
            JSONArray openidArray = data.getJSONArray("openid");
            String js = JSONObject.toJSONString(openidArray);
            List<String> list2 = JSONObject.parseArray(js, String.class);
            list.addAll(list2);
            //一次最多获取10000个openid
            if (jsonObjUserList.getIntValue("count") == 10000) {
                String nextId = jsonObjUserList.getString("next_openid");
                return forFansByTag(list, id, nextId);
            }
        }
        return list;
    }

    /**
     * 根据Id查询用户标签
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/getById")
    @ResponseBody
    public AjaxResult getById(Integer id) {
        logger.info("根据Id查询用户标签 id:{}", id);
        UserTag userTag = userTagService.getById(id);
        return AjaxResult.success(userTag);
    }

    /**
     * 分页查询
     *
     * @param searchEntity
     * @return
     */
    @RequestMapping(value = "/listForPage")
    @ResponseBody
    public AjaxResult listForPage(UserTag searchEntity) {
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();
        searchEntity.setAccount(mpAccount.getAccount());
        List<UserTag> list = userTagService.listForPage(searchEntity);
        if (CollectionUtils.isEmpty(list)) {
            return AjaxResult.success();
        }
        return getResult(searchEntity, list);
    }

    /**
     * 修改/添加
     *
     * @param entity
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/update")
    @ResponseBody
    public AjaxResult update(UserTag entity) throws WxErrorException {
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();
        entity.setAccount(mpAccount.getAccount());
        if (entity.getId() != null) {
            userTagService.update(entity);
            //更新成功
            return AjaxResult.updateSuccess();
        } else {
            //添加分两步
            //1. 调用微信API添加
            JSONObject tagName = new JSONObject();
            tagName.put("name", entity.getName());
            JSONObject tagjson = new JSONObject();
            tagjson.put("tag", tagName);
            String userTags = tagjson.toString();
            JSONObject userTag = WxApiClient.createUserTag(userTags, mpAccount);
            //2.添加到本地库
            if (userTag != null) {
                JSONObject returnUserTag = (JSONObject) userTag.get("tag");
                entity = JSONObject.parseObject(returnUserTag.toJSONString(), UserTag.class);
                entity.setAccount(mpAccount.getAccount());
                entity.setTagId(entity.getId());
                userTagService.add(entity);
                return AjaxResult.saveSuccess();
            }
            return AjaxResult.failure(Constants.MSG_ERROR);
        }
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/deleteBatchIds")
    @ResponseBody
    public AjaxResult deleteBatchIds(@RequestParam("ids[]") String[] ids) throws Exception {
        if (null != ids && ids.length > 0) {
            List<Integer> list = new ArrayList<>();
            int nums = 0;
            for (String id : ids) {
                UserTag tag = userTagService.getById(Integer.parseInt(id));
                Map<String, String> deleteUserTag = deleteUserTag(tag.getTagId());
                if ("true".equals(deleteUserTag.get("flag"))) {
                    list.add(Integer.parseInt(id));
                    nums++;
                }
            }
            if (nums == ids.length) {
                MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
                userTagService.deleteTTFByTagIds(mpAccount.getAccount(), list);
                userTagService.deleteBatchIds(list);
                return AjaxResult.deleteSuccess();
            }
            return AjaxResult.failure("删除失败");
        } else {
            logger.error("用户标签批量删除失败");
            return AjaxResult.failure("用户标签批量删除失败");
        }
    }

    /**
     * 单个删除标签
     *
     * @param userTag
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/delete")
    @ResponseBody
    public AjaxResult delete(UserTag userTag) throws Exception {
        UserTag tag = userTagService.getById(userTag.getId());
        //删除微信端标签
        Map<String, String> deleteUserTag = deleteUserTag(tag.getTagId());
        if ("true".equals(deleteUserTag.get("flag"))) {
            MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
            userTagService.deleteTTF(TagToFan.builder().account(mpAccount.getAccount()).tagId(tag.getTagId()).build());
            userTagService.delete(tag);
            return AjaxResult.deleteSuccess();
        }
        return AjaxResult.failure(deleteUserTag.get("msg"));
    }

    /**
     * 删除微信服务器的用户标签
     *
     * @param id
     * @return boolean
     */
    private Map<String, String> deleteUserTag(Integer id) throws Exception {
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
        JSONObject tag = new JSONObject();
        JSONObject tagId = new JSONObject();
        tagId.put("id", id);
        tag.put("tag", tagId);
        JSONObject result = WxApiClient.deleteUserTag(tag.toJSONString(), mpAccount);
        if (result != null && result.containsKey("errmsg")) {
            if ("ok".equals(result.get("errmsg").toString())) {
                return ImmutableMap.of("flag", "true");
            }
        }
        return ImmutableMap.of("flag", "false", "msg", result.get("errmsg").toString());
    }

    /**
     * 批量把用户移出标签
     *
     * @param id
     * @param openIds openid字符串 中间用“,”隔开的
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/removeUserForTag")
    @ResponseBody
    public AjaxResult removeUserForTag(Integer id, @RequestParam("openIds[]") String[] openIds) throws WxErrorException {
        logger.info("批量把用户移出标签 id:{},openids:{}", id, openIds.toString());
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
        String accessToken = WxApiClient.getAccessToken(mpAccount);
        List<String> asList = Arrays.asList(openIds);
        UserTag tag = userTagService.getById(id);
        //微信端批量为用户取消标签
        WxApi.batchUnTaggIng(accessToken, tag.getTagId(), asList);
        //本地批量移出中间表数据
        userTagService.deleteTTFByOpenIds(asList);

        //更新标签中的粉丝数量
        tag.setCount(tag.getCount() - asList.size());
        userTagService.update(tag);
        return AjaxResult.success();
    }

    /**
     * 批量把用户添加标签
     *
     * @param id
     * @param openIds
     * @return
     * @throws WxErrorException
     */
    @RequestMapping(value = "/addUserForTag")
    @ResponseBody
    public AjaxResult addUserForTag(Integer id, @RequestParam("openIds[]") String[] openIds) throws WxErrorException {
        logger.info("批量把用户添加标签 id:{},openids:{}", id, openIds.toString());
        MpAccount mpAccount = WxMemoryCacheClient.getMpAccount();//获取缓存中的唯一账号
        String accessToken = WxApiClient.getAccessToken(mpAccount);
        List<String> asList = Arrays.asList(openIds);
        UserTag tag = userTagService.getById(id);
        //微信端批量为用户添加标签
        JSONObject jsonObject = WxApi.batchTaggIng(accessToken, tag.getTagId(), asList);
        List<TagToFan> fanList = asList.parallelStream().map(openId -> TagToFan.builder()
                .tagId(tag.getTagId())
                .account(mpAccount.getAccount())
                .openId(openId).build())
                .collect(Collectors.toList());
        userTagService.addTagToUserList(fanList);
        //更新标签中的粉丝数量
        tag.setCount(asList.size() + tag.getCount());
        userTagService.update(tag);
        return AjaxResult.success();
    }
}
